<?php
namespace app\user\loglic;

class Captcha
{
    private $error = 'error_captcha';
    
    //最大错误次数
    private $errorMax = 6;
    
    //验证码值
    private $captcha = 0;
    
    //用户ID
    private $userId = 0;
    
    //是否封禁
    private $isBan = false;

    //发送类型
    private $sendType = '';
    
    //出错信息
    public function getError()
    {
        return lang($this->error);
    }
    
    //生成的验证码
    public function getCaptcha()
    {
        return $this->captcha;
    }
    
    //当前验证用户ID
    public function getUserId()
    {
        return $this->userId;
    }
    
    //当前客户端唯一ID
    public function clientId()
    {
        session_start();
        return session_id();
    }
    
    //获取通知列表（短信/邮箱）
    public function captchaList()
    {
        $notices = [];
        if(str_replace('off','',config('user.captcha_mobile'))){
            array_push($notices,'user_mobile');
        }
        if(str_replace('off','',config('user.captcha_email'))){
            array_push($notices,'user_email');
        }
        return $notices;
    }
    
    //发送验证码倒计时
    public function interval($tokenSession='', $tokenPost='')
    {
        //间隔时间
        $second = DcEmpty(config('user.captcha_interval'), 60);
        //客户端ID（依赖session）
        if(!$client = $this->clientId()){
            $this->error = 'error_request';
            return false;
        }
        //60秒内只能发送一次
        if(intval(cache($client))){
            $this->error = 'error_fast';
            return false;
        }
        //写入缓存
        cache($client, 1, $second);
        //第一次请求
        return true;
    }
    
    //（验证码登录）通过手机号、邮箱发送登录或注册验证码
    public function account($name='')
    {
        //当前用户ID
        if(!$this->accountId($name)){
            return false;
        }
        //生成验证码失败
        if(!$this->create($this->userId, 'account')){
            $this->error = 'error_captcha_empty';
            return false;
        }
        //调用消息发送接口
        return $this->send($this->sendType, $name);
    }
    
    //（修改密码）通过手机号、邮箱发送重置验证码
    public function reset($name='')
    {
        //获取用户ID
        if(!$this->userId($name)){
            return false;
        }
        //生成验证码失败
        if(!$this->create($this->userId, 'reset')){
            $this->error = 'error_captcha_empty';
            return false;
        }
        //调用消息发送接口
        return $this->send($this->sendType, $name);
    }
    
    //（重置邮箱）通过新邮箱地址发送重置验证码
    public function email($userId=0, $email='')
    {
        //验证地址唯一
        if(db('user')->where('user_email','eq',$email)->value('user_id')){
            $this->error = 'error_email_repeat';
            return false;
        }
        //生成验证码失败
        if(!$this->create($userId, 'email')){
            $this->error = 'error_captcha_empty';
            return false;
        }
        //调用消息发送接口
        return $this->send('email', $email);
    }
    
    //（重置手机）通过手机号发送重置验证码
    public function mobile($userId=0, $mobile='')
    {
        //验证号码唯一
        if(db('user')->where('user_mobile','eq',$mobile)->value('user_id')){
            $this->error = 'error_mobile_repeat';
            return false;
        }
        //生成验证码失败
        if(!$this->create($userId, 'mobile')){
            $this->error = 'error_captcha_empty';
            return false;
        }
        //调用消息发送接口
        return $this->send('mobile', $mobile);
    }
    
    //发送验证码（回调消息发送接品）
    private function send($type='', $name='')
    {
        $args = [
            'address' => $name,
            'captcha' => $this->captcha,
            'title'   => config("common.site_name").lang('user_captcha'),
            'content' => str_replace(
                ['[siteName]', '[captcha]', '[minute]'],
                [config("common.site_name"), $this->captcha, ceil(config('user.captcha_expire')/60)],
                config('user.captcha_content')
            ),
        ];
        $this->error = 'error_captcha_callback';
        if($type=='email' && config('user.captcha_email')){
            return model(config('user.captcha_email').'/Captcha','loglic')->send($args);
        }elseif($type=='mobile' && config('user.captcha_mobile')){
            return model(config('user.captcha_mobile').'/Captcha','loglic')->send($args);
        }else{
            $this->error = 'error_captcha_disabled';
            return false;
        }
    }
    
    //检测验证码是否正确（手机号或邮箱地址）
    public function check($name='', $logValue='', $logAction='reset')
    {
        if(!$name || !$logValue){
            $this->error = 'error_param';
            return false;
        }
        if(!$this->userId($name)){
            $this->error = 'error_user_empty';
            return false;
        }
        return $this->checkByUid($this->userId,$logValue,$logAction);
    }
    
    //检测验证码是否正确（用户ID）
    public function checkByUid($userId=0, $logValue='', $logAction='reset')
    {
        //获取通知日志
        if(!$logInfo=$this->logInfo($userId,$logAction)){
            $this->error = 'error_captcha_empty';
            return false;
        }
        //IP验证（防止欺骗）
        if(request()->ip()!=$logInfo['log_ip']){
            $this->error('error_request');
            return false;
        }
        //时间验证（超出有效期）
        if(time() > $logInfo['log_create_time']){
            $this->error = 'error_captcha_expire';
            return false;
        }
        //错误次数（防止暴力破解）
        if(intval($logInfo['log_type']) > $this->errorMax){
            $this->error = 'error_fast';
            return false;
        }
        //比较验证码
        if($logValue == $logInfo['log_value']){
            //重置验证码状态
            $this->logReset($logInfo['log_id'], 0);
            //返回验证结果
            return true;
        }
        //记录错误次数
        db('log')->where('log_id', $logInfo['log_id'])->setInc('log_type');
        //返回验证结果
        return false;
    }
    
    //通过手机号、邮箱返回用户ID（不存在时自动新建一个随机用户并返回ID）
    public function accountId($name='')
    {
        //是否已注册
        if($this->userId($name)){
            return $this->userId;
        }
        //是否已被封禁
        if($this->isBan){
            return 0;
        }
        //创建一个用户
        $user = array();
        $user['user_name']         = uniqid();
        $user['user_slug']         = $user['user_name'];
        $user['user_nice_name']    = $this->sendType.$user['user_name'];
        $user['user_pass']         = md5(time());
        $user['user_status']       = 'verify';
        $user['user_token']        = \daicuo\User::token_create(0);
        $user['user_create_time']  = false;
        $user['user_update_time']  = false;
        $user['user_expire']       = strtotime("+30 days");
        $user['user_capabilities'] = ['subscriber'];
        $user['user_pid']          = 0;
        $user['user_score']        = intval(config('user.score_register'));
        if($this->sendType=='email'){
            $user['user_email']    = $name;
        }elseif($this->sendType=='mobile'){
            $user['user_mobile']   = $name;
        }
        $this->userId = model('common/User','loglic')->write($user);
        return $this->userId;
    }
    
    //通过手机号、邮箱返回用户ID
    public function userId($name='')
    {
        if( is_email($name) ){
            $this->sendType = 'email';
            $result = db('user')->field('user_id,user_status')->where('user_email','eq',$name)->find();
        }elseif( is_mobile($name) ){
            $this->sendType = 'mobile';
            $result = db('user')->field('user_id,user_status')->where('user_mobile','eq',$name)->find();
        }
        //未找到用户
        if(!$result['user_id']){
            $this->error = 'error_user_empty';
            return 0;
        }
        //验证状态
        if(!in_array($result['user_status'],['normal','verify'])){
            $this->isBan = true;
            $this->error = 'error_user_status';
            return 0;
        }
        //定义当前用户
        $this->userId = $result['user_id'];
        //返回用户ID
        return $this->userId;
    }
    
    //通过用户ID生成验证码
    public function create($userId='', $action='reset')
    {
        //生成短信验证码
        $this->captcha = rand(100000,999999);
        //已存在验证码日志
        if($logInfo=$this->logInfo($userId, $action)){
            return $this->logReset($logInfo['log_id'], config('user.captcha_expire'));
        }
        //返回数据库操作结果
        return $this->logCreate($userId, $action);
    }
    
    /**
     * 增加验证码日志
     * @param array $userId 用户ID
     * @param int $logAction 验证码操作;reset|login
     * @return int 影响条数
     */
    private function logCreate($userId=0, $logAction='reset')
    {
        $data = [];
        $data['log_name']        = 'log_captcha_'.$logAction;
        $data['log_user_id']     = $userId;
        $data['log_info_id']     = 0;
        $data['log_value']       = $this->captcha;
        $data['log_module']      = 'user';
        $data['log_controll']    = 'captcha';
        $data['log_action']      = $logAction;
        $data['log_type']        = 0;//验证错误次数
        $data['log_ip']          = request()->ip();
        $data['log_create_time'] = time()+config('user.captcha_expire');
        return model('common/Log','loglic')->save($data);
    }
    
    //重置验证码日志
    private function logReset($logId=0, $expire=0)
    {
        $data = [
            'log_id'          => $logId,
            'log_type'        => 0,
            'log_ip'          => request()->ip(),
            'log_create_time' => time()+$expire,
        ];
        if($this->captcha){
            $data['log_value'] = $this->captcha;
        }
        return db('log')->update($data);
    }
    
    //返回验证码日志信息
    public function logInfo($userId=0, $logAction='reset')
    {
        return db('log')->where([
            'log_user_id'  => ['eq',$userId],
            'log_module'   => ['eq','user'],
            'log_controll' => ['eq','captcha'],
            'log_action'   => ['eq',$logAction],
        ])->find();
    }
}